Requires Scripting PRO
The CustomKeyboard namespace provides a comprehensive API for building fully custom keyboard UIs in the Scripting app. It allows you to create JSX-based keyboards, insert or modify text, query input state, respond to user interaction, and control keyboard layout or navigation.
You must define your keyboard interface in a file named **keyboard.tsx** inside your script project.
The CustomKeyboard API is only available in the keyboard extension environment.
It is not available in App scripts, Intents (intent.tsx), or Widgets (widget.tsx).
You must enable the keyboard in iOS settings:
Then tap the Scripting Keyboard and enable Allow Full Access to unlock clipboard and network features.
present(node: VirtualNode): voidRenders your custom keyboard UI using the given JSX node. This function must be called once in keyboard.tsx.
| Property | Type | Description |
|---|---|---|
textBeforeCursor |
Promise<string | null> |
Text before the cursor |
textAfterCursor |
Promise<string | null> |
Text after the cursor |
selectedText |
Promise<string | null> |
Currently selected text |
hasText |
Promise<boolean> |
Whether the text input contains any text |
useTraits(): TextInputTraitsHook to retrieve the current input traits (e.g., keyboard type, return key style). It automatically updates when textDidChange or selectionDidChange events occur.
traits: TextInputTraitsA snapshot of the traits at the last change. Prefer useTraits() in JSX components for reactivity.
keyboardType: 'default', 'numberPad', 'emailAddress'...returnKeyType: 'go', 'search', 'done'...autocapitalizationType: 'none', 'sentences', etc.textContentType: semantic input hints like 'username', 'oneTimeCode', etc.keyboardAppearance: 'light', 'dark', etc.insertText(text: string): Promise<void>Insert text at the current cursor position.
deleteBackward(): Promise<void>Delete one character before the cursor.
moveCursor(offset: number): Promise<void>Move the cursor by a number of characters. Negative = left; Positive = right.
setMarkedText(text, location, length): Promise<void>Mark a portion of inserted text (used in composition scenarios like Pinyin input).
unmarkText(): Promise<void>Clear any currently marked text.
dismiss(): Promise<void>Dismiss the keyboard view.
nextKeyboard(): Promise<void>Switch to the next system keyboard.
requestHeight(height: number): Promise<void>Request a new keyboard height in points. Recommended range is 216–360pt.
setHasDictationKey(value: boolean): Promise<void>Control whether the dictation (microphone) key is shown.
setToolbarVisible(visible: boolean): Promise<void>Show or hide the custom keyboard toolbar. Useful for debugging.
dismissToHome(): Promise<void>Dismisses the currently active keyboard script and returns to the Scripting keyboard home screen (script list). Useful for letting users choose another script.
playInputClick(): voidPlay the standard system keyboard click sound. Useful when simulating real key taps.
addListener(event, callback): voidRegister a listener for keyboard or text input changes.
| Event | Callback Signature | Description |
|---|---|---|
textWillChange |
() => void |
Before text changes |
textDidChange |
(traits: TextInputTraits) => void |
After text changes |
selectionWillChange |
() => void |
Before cursor/selection changes |
selectionDidChange |
(traits: TextInputTraits) => void |
After cursor/selection changes |
removeListener(event, callback): voidRemove a specific listener.
removeAllListeners(event): voidRemove all listeners for a given event type.
present() only once in your keyboard.tsx file.requestHeight() to ensure appropriate layout on different screen sizes.useTraits() for reactive input context access in JSX.dismissToHome() instead of dismiss() if you want to return to the script list.playInputClick() when simulating key taps for user feedback.hasText before calling deleteBackward().